const BaseHardware = require("./baseHardware.js");
const { exec } = require("child_process");
const os = require("os");
const { logger } = require("ee-core/log");
const { promisify } = require("util");

const execPromise = promisify(exec);

class IosHardwareService extends BaseHardware {
  async getCPUId() {
    try {
      const { stdout } = await execPromise(
        "ioreg -d2 -c IOPlatformExpertDevice | awk -F\\\" '/IOPlatformUUID/{print $(NF-1)}'"
      );
      const uuid = stdout.trim();

      if (uuid && uuid !== "") {
        return uuid.split("-").join("").substring(0, 16).toUpperCase();
      }

      return "Unknown";
    } catch (error) {
      logger.error("Error getting CPU ID on macOS:", error);
      return "Unknown";
    }
  }

  async getDiskSerialNumber() {
    try {
      const { stdout } = await execPromise(
        'system_profiler SPSerialATADataType SPNVMeDataType | grep "Serial Number"'
      );
      const lines = stdout.trim().split("\n");
      if (lines.length > 0) {
        // 提取序列号
        const serialLine = lines[0];
        const parts = serialLine.split(":");
        if (parts.length > 1) {
          return parts[1].replace(/\s+/g, "").replace(/\.$/, "");
        }
      }
      return "Unknown";
    } catch (error) {
      logger.error("Error getting Disk Serial Number on macOS:", error);
      return "Unknown";
    }
  }

  async _getGatewayAddress() {
    try {
      const { stdout } = await execPromise(
        'route get default | grep "gateway"'
      );
      const lines = stdout.trim().split("\n");
      if (lines.length > 0) {
        const gatewayLine = lines[0];
        const parts = gatewayLine.split(":");
        if (parts.length > 1) {
          return parts[1].trim();
        }
      }
      return "Unknown";
    } catch (error) {
      logger.error("Error getting Gateway Address on macOS:", error);
      return "Unknown";
    }
  }

  async _getGatewayMacAddress(gateway) {
    try {
      if (!gateway) {
        gateway = await this._getGatewayAddress();
      }

      if (gateway === "Unknown") {
        return "Unknown";
      }

      const { stdout } = await execPromise(
        `arp -n ${gateway} | grep "${gateway}"`
      );
      const lines = stdout.trim().split("\n");

      if (lines.length > 0) {
        const gatewayLine = lines[0];
        const parts = gatewayLine.trim().split(/\s+/);
        if (parts.length >= 4) {
          return parts[3] || "Unknown"; // MAC地址通常在第4列
        }
      }
      return "Unknown";
    } catch (error) {
      logger.error("Error getting Gateway MAC Address on macOS:", error);
      return "Unknown";
    }
  }

  // 获取网关集（interface IP => gateway IP）
  async _getGatewayMap() {
    try {
      const { stdout } = await execPromise("route -n get default");
      const lines = stdout.split("\n");

      const gatewayMap = {};
      let gatewayIp = "";
      let interfaceIp = "";

      // 查找网关IP
      for (const line of lines) {
        if (line.includes("gateway:")) {
          const parts = line.trim().split(/\s+/);
          gatewayIp = parts[1];
        }
        if (line.includes("interface:")) {
          const parts = line.trim().split(/\s+/);
          interfaceIp = parts[1];
        }
      }

      // 如果找到相关信息，则添加到映射中
      if (interfaceIp && gatewayIp) {
        // 在macOS上我们需要通过ifconfig获取接口IP
        try {
          const { stdout: ifconfigOut } = await execPromise(
            `ifconfig ${interfaceIp} | grep "inet "`
          );
          const inetLines = ifconfigOut.trim().split("\n");
          if (inetLines.length > 0) {
            const inetParts = inetLines[0].trim().split(/\s+/);
            if (inetParts.length >= 2) {
              const ip = inetParts[1];
              gatewayMap[ip] = gatewayIp;
            }
          }
        } catch (ifconfigError) {
          logger.warn("Error getting interface IP on macOS:", ifconfigError);
        }
      }

      return gatewayMap;
    } catch (error) {
      logger.error("Error getting Gateway Map on macOS:", error);
      return {};
    }
  }

  // 获取 MAC 地址和描述信息
  async _getMacAddressAndDescriptionMap() {
    try {
      const { stdout } = await execPromise(
        "networksetup -listallhardwareports"
      );
      const lines = stdout.split("\n");

      const macDescMap = {};
      let currentPort = "";

      for (let line of lines) {
        line = line.trim();
        if (line.startsWith("Hardware Port:")) {
          const parts = line.split(":");
          currentPort = parts.length > 1 ? parts[1].trim() : "";
        }else if (line.startsWith("Ethernet Address:")) {
          const parts = line.split(":");
          if (parts.length > 1) {
            const macWithDevice = parts.slice(1).join(":").trim(); // 格式如 "aa:bb:cc:dd:ee:ff"
            const macMatch = macWithDevice.match(/^([a-fA-F0-9:]{17})/);
            if (macMatch && currentPort) {
              const mac = macMatch[1];
              macDescMap[mac.toLowerCase()] = currentPort;
            }
          }
        }
      }
      return macDescMap;
    } catch (error) {
      logger.error(
        "Error getting MAC Address and Description Map on macOS:",
        error
      );
      return {};
    }
  }

    // 获取 Device 和描述信息
  async _getDeviceAndDescriptionMap() {
      try {
        const { stdout } = await execPromise(
          "networksetup -listallhardwareports"
        );
        const lines = stdout.split("\n");
  
        const macDescMap = {};
        let currentPort = "";
  
        for (let line of lines) {
          line = line.trim();
          if (line.startsWith("Hardware Port:")) {
            const parts = line.split(":");
            currentPort = parts.length > 1 ? parts[1].trim() : "";
          } else if (line.startsWith("Device:")) {
            const parts = line.split(":");
            if (parts.length > 1) {
              macDescMap[parts[1].trim()] = currentPort;
            }
          }
        }
        return macDescMap;
      } catch (error) {
        logger.error(
          "Error getting MAC Address and Description Map on macOS:",
          error
        );
        return {};
      }
    }

  async getNetworkDetails() {
    try {
      const interfaces = os.networkInterfaces();
      const infoList = [];

      // 获取网关（IP -> 网关）
      const gatewayMap = await this._getGatewayMap().catch((err) => {
        logger.error("获取网关映射失败:", err.message);
        return {};
      });

      // device地址和描述
      const deviceAndDescriptionMap =
        await this._getDeviceAndDescriptionMap().catch((err) => {
          logger.error("获取device和描述失败:", err.message);
          return {};
        });

      const gatewayIps = [...new Set(Object.values(gatewayMap))];

      // 获取网关 MAC 地址
      const gatewayMacMap = {};
      for (const gw of gatewayIps) {
        try {
          const mac = await this._getGatewayMacAddress(gw);
          if (mac) gatewayMacMap[gw] = mac;
        } catch (error) {
          logger.warn(`获取网关 ${gw} 的 MAC 地址失败:`, error.message);
        }
      }

      // 收集符合条件的网络接口信息
      for (const ifname in interfaces) {
        for (const iface of interfaces[ifname]) {
          if (
            !iface.internal &&
            iface.mac !== "00:00:00:00:00:00" &&
            iface.family === "IPv4"
          ) {
            // 在macOS上查找对应的网关
            let gatewayIp = "Unknown";
            for (const [localIp, gwIp] of Object.entries(gatewayMap)) {
              if (localIp === iface.address) {
                gatewayIp = gwIp;
                break;
              }
            }

            const gatewayMac = gatewayMacMap[gatewayIp] || "Unknown";
            const description =
            deviceAndDescriptionMap[ifname] || "Unknown";

            if (gatewayMac != "Unknown") {
              // 找不到的不要
              infoList.push({
                ip: iface.address,
                interface: ifname,
                mac: iface.mac,
                gateway: gatewayIp,
                gatewayMac: gatewayMac,
                description: description,
              });
            }
          }
        }
      }

      return infoList;
    } catch (error) {
      logger.error("Error getting Network Details on macOS:", error);
      return [];
    }
  }

  // 添加 networkCardDrive 方法
  async networkCardDrive() {
    // 在 macOS 上获取网络接口信息
    try {
      const networkCards = await this._getMacAddressAndDescriptionMap();
      const result = [];

      // 将 Map 转换为所需格式的数组
      let index = 0;
      for (const [mac, description] of Object.entries(networkCards)) {
        const serviceName = this.macToGuid(mac); // 使用 macToGuid 方法转换 MAC 地址为 GUID
        result.push({
          name: index.toString(),
          ServiceName: serviceName,
          Description: description,
        });
        index++;
      }

      return result;
    } catch (error) {
      logger.error("Error getting Network Card information on macOS:", error);
      return [];
    }
  }

  /**
   * 将MAC地址转换为GUID格式
   * @param {string} mac - MAC地址，格式如 "00:e0:4c:14:f3:ac"
   * @returns {string} GUID格式的字符串，如 "{ABA0566B-EECB-4BD7-81F0-93EB4AF65997}"
   */
  macToGuid(mac) {
    // 验证并清理MAC地址
    const cleanMac = mac.replace(/-/g, ":").toLowerCase();
    if (!/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/.test(cleanMac)) {
      throw new Error("Invalid MAC address format");
    }

    // 分割MAC地址为字节数组
    const macBytes = cleanMac.split(":").map((hex) => parseInt(hex, 16));

    // 构造16字节的GUID数据
    // 前6个字节是MAC地址
    // 后10个字节通过特定算法生成，保证可逆性
    const guidBytes = new Array(16);

    // 复制MAC地址到前6个字节
    for (let i = 0; i < 6; i++) {
      guidBytes[i] = macBytes[i];
    }

    // 填充剩余的10个字节，使用固定的模式保证可逆
    // 这里使用一种简单的模式：交替使用0xFF和MAC字节的补码
    guidBytes[6] = 0xff;
    guidBytes[7] = ~macBytes[0] & 0xff;
    guidBytes[8] = 0xff;
    guidBytes[9] = ~macBytes[1] & 0xff;
    guidBytes[10] = 0xff;
    guidBytes[11] = ~macBytes[2] & 0xff;
    guidBytes[12] = 0xff;
    guidBytes[13] = ~macBytes[3] & 0xff;
    guidBytes[14] = 0xff;
    guidBytes[15] = ~macBytes[4] & 0xff;

    // 格式化为GUID字符串
    const toHex = (byte) => byte.toString(16).padStart(2, "0").toUpperCase();

    const part1 = guidBytes.slice(0, 4).reverse().map(toHex).join(""); // 反转前4字节
    const part2 = guidBytes.slice(4, 6).reverse().map(toHex).join(""); // 反转接下来2字节
    const part3 = guidBytes.slice(6, 8).reverse().map(toHex).join(""); // 反转接下来2字节
    const part4 = guidBytes.slice(8, 10).map(toHex).join("");
    const part5 = guidBytes.slice(10, 16).map(toHex).join("");

    return `{${part1}-${part2}-${part3}-${part4}-${part5}}`;
  }

  /**
   * 将GUID格式转换回MAC地址
   * @param {string} guid - GUID格式的字符串，如 "{ABA0566B-EECB-4BD7-81F0-93EB4AF65997}"
   * @returns {string} MAC地址，格式如 "00:e0:4c:14:f3:ac"
   */
  guidToMac(guid) {
    // 验证并清理GUID
    const cleanGuid = guid.replace(/[{}]/g, "");
    if (
      !/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/.test(
        cleanGuid
      )
    ) {
      throw new Error("Invalid GUID format");
    }

    // 解析GUID为字节数组
    const parts = cleanGuid.split("-");
    const bytes = [];

    // 解析各部分并转换为字节
    const parsePart = (part, byteCount) => {
      const partBytes = [];
      for (let i = 0; i < byteCount * 2; i += 2) {
        partBytes.push(parseInt(part.substr(i, 2), 16));
      }
      return partBytes;
    };

    // 注意：前三个部分需要反转字节顺序
    bytes.push(...parsePart(parts[0], 4).reverse()); // 4 bytes
    bytes.push(...parsePart(parts[1], 2).reverse()); // 2 bytes
    bytes.push(...parsePart(parts[2], 2).reverse()); // 2 bytes
    bytes.push(...parsePart(parts[3], 2)); // 2 bytes
    bytes.push(...parsePart(parts[4], 6)); // 6 bytes

    // 提取前6个字节作为MAC地址
    const macBytes = bytes.slice(0, 6);

    // 验证可逆性（验证填充字节是否符合我们的模式）
    if (
      bytes[6] !== 0xff ||
      bytes[7] !== (~macBytes[0] & 0xff) ||
      bytes[8] !== 0xff ||
      bytes[9] !== (~macBytes[1] & 0xff) ||
      bytes[10] !== 0xff ||
      bytes[11] !== (~macBytes[2] & 0xff) ||
      bytes[12] !== 0xff ||
      bytes[13] !== (~macBytes[3] & 0xff) ||
      bytes[14] !== 0xff ||
      bytes[15] !== (~macBytes[4] & 0xff)
    ) {
      throw new Error(
        "GUID was not created with this algorithm or has been modified"
      );
    }

    // 格式化为MAC地址
    return macBytes
      .map((byte) => byte.toString(16).padStart(2, "0").toLowerCase())
      .join(":");
  }
}

module.exports = {
  IosHardwareService,
  iosHardwareService: new IosHardwareService(),
};
